import os
import cv2
import numpy as np
from datetime import datetime
from feature_extractor import FeatureExtractor
from tqdm import tqdm


class Comparison:
    def __init__(self, videos, prefs):
        self.videos = videos
        self.prefs = prefs
        self.matches = []
        self.clip_matches = []
        self.mashup_matches = []
        self.feature_extractor = FeatureExtractor()  # 特征提取器

    def _detect_mashup(self, target_video):
        """检测混剪视频"""
        mashup_segments = []

        # 对目标视频的每个场景
        for segment in tqdm(target_video.scene_segments):
            best_match = None
            best_similarity = 0

            # 与所有源视频比较
            for source_video in self.videos:
                if source_video == target_video:
                    continue

                # 比较当前场景与源视频的所有场景
                for source_segment in source_video.scene_segments:
                    similarity = self._compare_segments(
                        segment['frames'],
                        source_segment['frames']
                    )

                    if similarity > best_similarity and similarity > 0.8:
                        best_similarity = similarity
                        best_match = {
                            'source_video': source_video,
                            'source_segment': source_segment,
                            'similarity': similarity
                        }

            if best_match:
                mashup_segments.append({
                    'target_segment': segment,
                    'source_match': best_match
                })

        # 如果找到足够的匹配片段，认为是混剪
        if len(mashup_segments) >= 3:  # 至少3个片段匹配
            self.mashup_matches.append({
                'target_video': target_video,
                'segments': mashup_segments
            })

    def _compare_segments(self, segment1, segment2):
        """比较两个视频片段的相似度"""
        if not segment1 or not segment2:
            return 0.0

        # 取每个片段的中间帧进行比较
        mid_frame1 = segment1[len(segment1) // 2]
        mid_frame2 = segment2[len(segment2) // 2]

        # 提取特征
        feature1 = self.feature_extractor.extract_frame_feature(mid_frame1)
        feature2 = self.feature_extractor.extract_frame_feature(mid_frame2)

        # 计算相似度
        return self._compare_frame_features(feature1, feature2)

    def report_matching_videos(self):
        print("\n正在比较视频...")

        # 检测混剪
        for video in self.videos:
            self._detect_mashup(video)

        # 原有的比较逻辑
        for i in range(len(self.videos)):
            for j in range(i + 1, len(self.videos)):
                similarity = self.compare_videos(self.videos[i], self.videos[j])
                if similarity > self.prefs._thresholdSSIM:
                    self.matches.append({
                        'video1': self.videos[i],
                        'video2': self.videos[j],
                        'similarity': similarity
                    })

        self._print_results()

    def compare_videos(self, video1, video2):
        # 1. 基本比较（时长、分辨率等）
        if not self._basic_comparison(video1, video2):
            return 0.0

        # 2. 整体相似度比较
        overall_similarity = self._calculate_overall_similarity(video1, video2)

        # 3. 剪辑片段检测
        clip_similarity = self._detect_clips(video1, video2)

        # 4. 综合相似度
        return max(overall_similarity, clip_similarity)

    def _basic_comparison(self, video1, video2):
        """基本属性比较"""
        # 时长差异检查（允许10%的差异）
        duration_diff = abs(video1.duration - video2.duration)
        if duration_diff > max(video1.duration, video2.duration) * 0.1:
            return False

        # 分辨率检查
        if video1.width != video2.width or video1.height != video2.height:
            return False

        return True

    def _calculate_overall_similarity(self, video1, video2):
        """计算整体相似度"""
        ssim_similarity = self._calculate_ssim(video1, video2)
        phash_similarity = self._calculate_phash_similarity(video1, video2)
        return (ssim_similarity + phash_similarity) / 2

    def _calculate_ssim(self, video1, video2):
        total_ssim = 0
        count = 0

        for i in range(len(video1.grayThumb)):
            if i >= len(video2.grayThumb):
                break

            ssim_value = self._compute_ssim(
                video1.grayThumb[i],
                video2.grayThumb[i]
            )
            total_ssim += ssim_value
            count += 1

        return total_ssim / count if count > 0 else 0

    def _compute_ssim(self, img1, img2):
        C1 = (0.01 * 255) ** 2
        C2 = (0.03 * 255) ** 2

        img1 = img1.astype(np.float64)
        img2 = img2.astype(np.float64)
        kernel = cv2.getGaussianKernel(11, 1.5)
        window = np.outer(kernel, kernel.transpose())

        mu1 = cv2.filter2D(img1, -1, window)[5:-5, 5:-5]
        mu2 = cv2.filter2D(img2, -1, window)[5:-5, 5:-5]
        mu1_sq = mu1 ** 2
        mu2_sq = mu2 ** 2
        mu1_mu2 = mu1 * mu2
        sigma1_sq = cv2.filter2D(img1 ** 2, -1, window)[5:-5, 5:-5] - mu1_sq
        sigma2_sq = cv2.filter2D(img2 ** 2, -1, window)[5:-5, 5:-5] - mu2_sq
        sigma12 = cv2.filter2D(img1 * img2, -1, window)[5:-5, 5:-5] - mu1_mu2

        ssim_map = ((2 * mu1_mu2 + C1) * (2 * sigma12 + C2)) / ((mu1_sq + mu2_sq + C1) * (sigma1_sq + sigma2_sq + C2))
        return ssim_map.mean()

    def _calculate_phash_similarity(self, video1, video2):
        total_similarity = 0
        count = 0

        for i in range(len(video1.hash)):
            if i >= len(video2.hash):
                break

            if video1.hash[i] == 0 or video2.hash[i] == 0:
                continue

            # 计算汉明距离
            hamming_distance = bin(video1.hash[i] ^ video2.hash[i]).count('1')
            similarity = 1 - (hamming_distance / 64)  # 64是pHash的位数
            total_similarity += similarity
            count += 1

        return total_similarity / count if count > 0 else 0

    def _detect_clips(self, video1, video2):
        """检测剪辑片段"""
        max_similarity = 0.0
        clip_matches = []

        # 对每个关键帧进行比较
        for i, frame1 in enumerate(video1.key_frames):
            if i >= len(video1.frame_features):
                continue
            for j, frame2 in enumerate(video2.key_frames):
                if j >= len(video2.frame_features):
                    continue
                similarity = self._compare_frame_features(
                    video1.frame_features[i],
                    video2.frame_features[j]
                )

                if similarity > 0.8:  # 阈值可调整
                    # 检查时间连续性
                    if self._check_temporal_continuity(
                            video1.scene_changes[i:],
                            video2.scene_changes[j:],
                            similarity
                    ):
                        clip_matches.append({
                            'start1': video1.scene_changes[i],
                            'start2': video2.scene_changes[j],
                            'similarity': similarity
                        })
                        max_similarity = max(max_similarity, similarity)

        if clip_matches:
            self.clip_matches.append({
                'video1': video1,
                'video2': video2,
                'clips': clip_matches
            })

        return max_similarity

    def _compare_frame_features(self, feature1, feature2):
        """比较帧特征"""
        # 1. 比较颜色直方图
        hist_similarity = cv2.compareHist(
            feature1['hist'],
            feature2['hist'],
            cv2.HISTCMP_CORREL
        )

        # 2. 比较边缘密度
        edge_similarity = 1 - abs(feature1['edge_density'] - feature2['edge_density'])

        # 3. 比较DCT特征
        dct_diff = np.mean(np.abs(feature1['dct'] - feature2['dct']))
        dct_similarity = 1 - min(dct_diff, 1.0)

        # 综合相似度
        return (hist_similarity + edge_similarity + dct_similarity) / 3

    def _check_temporal_continuity(self, scenes1, scenes2, initial_similarity):
        """检查时间连续性"""
        if len(scenes1) < 2 or len(scenes2) < 2:
            return False

        # 检查后续帧的相似度
        for i in range(1, min(len(scenes1), len(scenes2))):
            time_diff1 = scenes1[i] - scenes1[i - 1]
            time_diff2 = scenes2[i] - scenes2[i - 1]

            # 如果时间差异太大，认为不连续
            if abs(time_diff1 - time_diff2) > 1.0:  # 1秒阈值
                return False

        return True

    def _print_results(self):
        if not self.matches and not self.clip_matches and not self.mashup_matches:
            print("\n未找到重复视频。")
            return

        print("\n=== 完整视频匹配 ===")
        for match in self.matches:
            self._print_video_match(match)

        print("\n=== 剪辑片段匹配 ===")
        for clip_match in self.clip_matches:
            self._print_clip_match(clip_match)

        print("\n=== 混剪视频匹配 ===")
        for mashup_match in self.mashup_matches:
            self._print_mashup_match(mashup_match)

        self._save_results_to_file()

    def _print_video_match(self, match):
        """打印完整视频匹配结果"""
        video1 = match['video1']
        video2 = match['video2']
        similarity = match['similarity']

        print("\n" + "=" * 80)
        print(f"相似度: {similarity:.2%}")
        print(f"视频1: {os.path.basename(video1.filename)}")
        print(f"  路径: {video1.filename}")
        print(f"  时长: {video1.duration / 1000:.1f}秒")
        print(f"  分辨率: {video1.width}x{video1.height}")
        print(f"  大小: {video1.size / 1024 / 1024:.1f}MB")

        print(f"\n视频2: {os.path.basename(video2.filename)}")
        print(f"  路径: {video2.filename}")
        print(f"  时长: {video2.duration / 1000:.1f}秒")
        print(f"  分辨率: {video2.width}x{video2.height}")
        print(f"  大小: {video2.size / 1024 / 1024:.1f}MB")
        print("=" * 80)

    def _print_clip_match(self, clip_match):
        """打印剪辑片段匹配结果"""
        video1 = clip_match['video1']
        video2 = clip_match['video2']

        print(f"\n发现剪辑片段匹配:")
        print(f"源视频: {os.path.basename(video1.filename)}")
        print(f"目标视频: {os.path.basename(video2.filename)}")

        for clip in clip_match['clips']:
            print(f"\n片段匹配:")
            print(f"  源视频时间: {clip['start1']:.1f}秒")
            print(f"  目标视频时间: {clip['start2']:.1f}秒")
            print(f"  相似度: {clip['similarity']:.2%}")

    def _print_mashup_match(self, mashup_match):
        target_video = mashup_match['target_video']
        print(f"\n发现混剪视频: {os.path.basename(target_video.filename)}")
        print("包含以下源视频片段:")

        for segment in mashup_match['segments']:
            source_video = segment['source_match']['source_video']
            source_segment = segment['source_match']['source_segment']
            target_segment = segment['target_segment']

            print(f"\n片段匹配:")
            print(f"  源视频: {os.path.basename(source_video.filename)}")
            print(f"  源视频时间: {source_segment['start']:.1f}秒 - {source_segment['end']:.1f}秒")
            print(f"  目标视频时间: {target_segment['start']:.1f}秒 - {target_segment['end']:.1f}秒")
            print(f"  相似度: {segment['source_match']['similarity']:.2%}")

    def _save_results_to_file(self):
        timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
        result_file = f"duplicate_videos_{timestamp}.txt"

        with open(result_file, "w", encoding="utf-8") as f:
            f.write(f"视频去重结果 - {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}\n")

            if self.matches:
                f.write(f"\n=== 完整视频匹配 ===\n")
                f.write(f"共发现 {len(self.matches)} 组重复视频\n\n")
                for match in self.matches:
                    self._write_video_match(f, match)

            if self.clip_matches:
                f.write(f"\n=== 剪辑片段匹配 ===\n")
                f.write(f"共发现 {len(self.clip_matches)} 组剪辑片段\n\n")
                for clip_match in self.clip_matches:
                    self._write_clip_match(f, clip_match)

            if self.mashup_matches:
                f.write(f"\n=== 混剪视频匹配 ===\n")
                f.write(f"共发现 {len(self.mashup_matches)} 个混剪视频\n\n")
                for mashup_match in self.mashup_matches:
                    self._write_mashup_match(f, mashup_match)

        print(f"\n结果已保存到文件: {result_file}")

    def _write_video_match(self, f, match):
        video1 = match['video1']
        video2 = match['video2']
        similarity = match['similarity']

        f.write("=" * 80 + "\n")
        f.write(f"相似度: {similarity:.2%}\n")
        f.write(f"视频1: {video1.filename}\n")
        f.write(f"  时长: {video1.duration / 1000:.1f}秒\n")
        f.write(f"  分辨率: {video1.width}x{video1.height}\n")
        f.write(f"  大小: {video1.size / 1024 / 1024:.1f}MB\n")

        f.write(f"\n视频2: {video2.filename}\n")
        f.write(f"  时长: {video2.duration / 1000:.1f}秒\n")
        f.write(f"  分辨率: {video2.width}x{video2.height}\n")
        f.write(f"  大小: {video2.size / 1024 / 1024:.1f}MB\n")
        f.write("=" * 80 + "\n\n")

    def _write_clip_match(self, f, clip_match):
        video1 = clip_match['video1']
        video2 = clip_match['video2']

        f.write("=" * 80 + "\n")
        f.write(f"剪辑片段匹配: {os.path.basename(video1.filename)} 和 {os.path.basename(video2.filename)}\n")
        f.write("=" * 80 + "\n")

        for clip in clip_match['clips']:
            f.write(f"  源视频时间: {clip['start1']:.1f}秒\n")
            f.write(f"  目标视频时间: {clip['start2']:.1f}秒\n")
            f.write(f"  相似度: {clip['similarity']:.2%}\n")
            f.write("=" * 80 + "\n")

    def _write_mashup_match(self, f, mashup_match):
        target_video = mashup_match['target_video']
        f.write("=" * 80 + "\n")
        f.write(f"混剪视频: {os.path.basename(target_video.filename)}\n")
        f.write("包含以下源视频片段:\n")

        for segment in mashup_match['segments']:
            source_video = segment['source_match']['source_video']
            source_segment = segment['source_match']['source_segment']
            target_segment = segment['target_segment']

            f.write(f"\n片段匹配:\n")
            f.write(f"  源视频: {os.path.basename(source_video.filename)}\n")
            f.write(f"  源视频时间: {source_segment['start']:.1f}秒 - {source_segment['end']:.1f}秒\n")
            f.write(f"  目标视频时间: {target_segment['start']:.1f}秒 - {target_segment['end']:.1f}秒\n")
            f.write(f"  相似度: {segment['source_match']['similarity']:.2%}\n")

        f.write("=" * 80 + "\n")